﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AzureGames.Model;
using AzureGames.Model.Statistics;

namespace AzureGames.Data.InMemory
{
    public class StatisticsRepository : IUserStatisticsRepository, IGameStatisticsRepository
    {
        private static List<GameStatistics> _games = GetInitialGameStatistics();

        private static List<GameStatistics> GetInitialGameStatistics()
        {
            var games = new List<GameStatistics>();

            // today's values are fixed to ease testing
            games.Add(new GameStatistics
            {
            CancelledGames = 2,
            CompletedGames = 3,
            CreatedGames = 5,
            Date = DateTime.Today,
            GameDefinitionID = 1,
            GameType = GameType.MultiplePlayer
            });
            games.Add(new GameStatistics
            {
                CancelledGames = 1,
                CompletedGames = 11,
                CreatedGames = 2,
                Date = DateTime.Today,
                GameDefinitionID = 1,
                GameType = GameType.SinglePlayer
            });

            games.Add(new GameStatistics
            {
                CancelledGames = 1,
                CompletedGames = 4,
                CreatedGames = 2,
                Date = DateTime.Today,
                GameDefinitionID = 2,
                GameType = GameType.MultiplePlayer
            });
            games.Add(new GameStatistics
            {
                CancelledGames = 2,
                CompletedGames = 12,
                CreatedGames = 4,
                Date = DateTime.Today,
                GameDefinitionID = 2,
                GameType = GameType.SinglePlayer
            });

            var rand = new Random();

            for (int i = 1; i < 30; i++)
            {
                for (int g = 1; g <= 2; g++)
                {
                    games.Add(new GameStatistics
                    {
                        CancelledGames = rand.Next(0,20),
                        CompletedGames = rand.Next(0, 20),
                        CreatedGames = rand.Next(0, 20),
                        Date = DateTime.Today.AddDays(-(i)),
                        GameDefinitionID = g,
                        GameType = GameType.MultiplePlayer
                    });
                    games.Add(new GameStatistics
                    {
                        CancelledGames = rand.Next(0, 20),
                        CompletedGames = rand.Next(0, 20),
                        CreatedGames = rand.Next(0, 20),
                        Date = DateTime.Today.AddDays(-(i)),
                        GameDefinitionID = g,
                        GameType = GameType.SinglePlayer
                    });
                }
            }

            return games;
        }

        private static List<UserStatistics> _users = new List<UserStatistics>();
        private object _lock = new object();


        public List<GameStatistics> GetGameStatistics(int gameDefinitionID, RANGE range)
        {
            DateTime fromDate = GetDateMaxRange(range);
            return _games.Where(game => game.Date > fromDate && game.GameDefinitionID == gameDefinitionID).ToList();
        }

        public List<UserStatistics> GetUserStatistics(int gameDefinitionID, string playerID, RANGE range)
        {
            DateTime fromDate = GetDateMaxRange(range);
            return _users.Where(game => game.Date > fromDate && game.GameDefinitionID == gameDefinitionID && game.PlayerID == playerID).ToList();
        }

        private DateTime GetDateMaxRange(RANGE range)
        {
            switch (range)
            {
                default:
                case RANGE.Today:
                    return DateTime.Now.Date;
                case RANGE.ThisWeek:
                    return DateTime.Now.Date.AddDays(-7);
                case RANGE.ThisYear:
                    return DateTime.Now.Date.AddYears(-1);
                case RANGE.ThisMonth:
                    return DateTime.Now.Date.AddMonths(-1);
            }
        }

        public void AddGameStatistic(int gameDefinitionID, GameType gameType, DateTime date, int state)
        {
            lock (_lock)
            {
                var gameStatistic = _games.FirstOrDefault(g => g.GameDefinitionID == gameDefinitionID && g.Date == date.Date && g.GameType == gameType);

                if (gameStatistic == null)
                    _games.Add(new GameStatistics
                    {
                        CancelledGames = state == Board.Cancelled ? 1 : 0,
                        CompletedGames = state == Board.Completed ? 1 : 0,
                        CreatedGames = state == Board.Created ? 1 : 0,
                        Date = date.Date,
                        GameDefinitionID = gameDefinitionID,
                        GameType = gameType
                    });
                else
                {
                    switch (state)
                    {
                        case Board.Completed:                            
                            gameStatistic.CompletedGames += 1;
                            break;
                        case Board.Created:
                            gameStatistic.CreatedGames += 1;
                            break;
                        case Board.Cancelled:                            
                            gameStatistic.CancelledGames += 1;
                            break;
                    }
                }
            }
        }

        public void AddUserStatistic(int gameDefinitionID, GameType gameType, DateTime date, string playerID, int state)
        {
            lock (_lock)
            {
                var userStatistic = _users.FirstOrDefault(u => u.GameDefinitionID == gameDefinitionID
                                                               && u.Date == date.Date
                                                               && u.GameType == gameType
                                                               && u.PlayerID == playerID);
                if (userStatistic == null)
                    _users.Add(new UserStatistics
                    {
                        CancelledGames = state == Board.Cancelled ? 1 : 0,
                        CompletedGames = state == Board.Completed ? 1 : 0,
                        CreatedGames = state == Board.Created ? 1 : 0,
                        Date = date.Date,
                        GameDefinitionID = gameDefinitionID,
                        GameType = gameType,
                        PlayerID = playerID
                    });
                else
                {
                    switch (state)
                    {
                        case Board.Completed:
                            userStatistic.CompletedGames += 1;
                            break;
                        case Board.Created:
                            userStatistic.CreatedGames += 1;
                            break;
                        case Board.Cancelled:
                            userStatistic.CancelledGames += 1;
                            break;
                    }
                }
            }
        }


        public void RemoveGameStatistic(int gameDefinitionID, GameType gameType, DateTime date, int state)
        {
            lock (_lock)
            {
                var gameStatistic = _games.FirstOrDefault(g => g.GameDefinitionID == gameDefinitionID && g.Date == date.Date && g.GameType == gameType);

                if (gameStatistic == null)
                    _games.Add(new GameStatistics
                    {
                        CancelledGames = 0,
                        CompletedGames = 0,
                        CreatedGames = 0,
                        Date = date.Date,
                        GameDefinitionID = gameDefinitionID,
                        GameType = gameType
                    });
                else
                {
                    switch (state)
                    {
                        case Board.Completed:
                            gameStatistic.CompletedGames -= 1;
                            break;
                        case Board.Created:
                            gameStatistic.CreatedGames -= 1;
                            break;
                        case Board.Cancelled:
                            gameStatistic.CancelledGames -= 1;
                            break;
                    }
                }
            }
        }

        public void RemoveUserStatistic(int gameDefinitionID, GameType gameType, DateTime date, string playerID, int state)
        {
            lock (_lock)
            {
                var userStatistic = _users.FirstOrDefault(u => u.GameDefinitionID == gameDefinitionID
                                                               && u.Date == date.Date
                                                               && u.GameType == gameType
                                                               && u.PlayerID == playerID);
                if (userStatistic == null)
                    _users.Add(new UserStatistics
                    {
                        CancelledGames = 0,
                        CompletedGames = 0,
                        CreatedGames = 0,
                        Date = date.Date,
                        GameDefinitionID = gameDefinitionID,
                        GameType = gameType,
                        PlayerID = playerID
                    });
                else
                {
                    switch (state)
                    {
                        case Board.Completed:
                            userStatistic.CompletedGames -= 1;
                            break;
                        case Board.Created:
                            userStatistic.CreatedGames -= 1;
                            break;
                        case Board.Cancelled:
                            userStatistic.CancelledGames -= 1;
                            break;
                    }
                }
            }
        }
    }
}
